package butines.core.math;

public strictfp class Vector2f {
	
	public float x;
	public float y;

	// Constructor
	public Vector2f() {

	}

	public Vector2f(float x, float y) {
		this.x = x;
		this.y = y;
	}

	public Vector2f(Vector2f other) {
		this.x = other.x;
		this.y = other.y;
	}

	public Vector2f copy() {
		return new Vector2f(this);
	}

	// Setter
	public Vector2f set(float x, float y) {
		this.x = x;
		this.y = y;
		return this;
	}

	public Vector2f set(Vector2f other) {
		this.x = other.x;
		this.y = other.y;
		return this;
	}

	// Add
	public Vector2f add(float x, float y) {
		this.x += x;
		this.y += y;
		return this;
	}

	public Vector2f add(Vector2f other) {
		this.x += other.x;
		this.y += other.y;
		return this;
	}

	public Vector2f add(Vector2f v1, Vector2f v2) {
		this.x = v1.x + v2.x;
		this.y = v1.y + v2.y;
		return this;
	}

	// Sub
	public Vector2f sub(float x, float y) {
		this.x -= x;
		this.y -= y;
		return this;
	}

	public Vector2f sub(Vector2f other) {
		this.x -= other.x;
		this.y -= other.y;
		return this;
	}

	public Vector2f sub(Vector2f v1, Vector2f v2) {
		this.x = v1.x - v2.x;
		this.y = v1.y - v2.y;
		return this;
	}

	// Mult
	public Vector2f mult(float value) {
		x *= value;
		y *= value;
		return this;
	}

	public Vector2f mult(Vector2f vec, float value) {
		x = vec.x * value;
		y = vec.y * value;
		return this;
	}

	// Div
	public Vector2f div(float value) {
		x /= value;
		y /= value;
		return this;
	}

	public Vector2f div(Vector2f vec, float value) {
		x = vec.x / value;
		y = vec.y / value;
		return this;
	}

	// Negate
	public Vector2f negate() {
		x = -x;
		y = -y;
		return this;
	}

	public Vector2f negate(Vector2f vec) {
		x = -vec.x;
		y = -vec.y;
		return this;
	}
	
	// Length
	public float lengthSq() {
		return x * x + y * y;
	}

	public float length() {
		return (float) Math.sqrt(x * x + y * y);
	}

	// normalise
	public Vector2f normalise() {
		float norm = 1.0f / length();
		this.x = x * norm;
		this.y = y * norm;
		return this;
	}

	public Vector2f normalise(Vector2f vec) {
		float norm = 1.0f / vec.length();
		this.x = vec.x * norm;
		this.y = vec.y * norm;
		return this;
	}

	// Utils
	public float dot(Vector2f other) {
		return this.x * other.x + this.y * other.y;
	}
	
	public float angle(Vector2f other) {
		float dot = this.dot(other) / (this.length() * other.length());
		if (dot < -1.0f) {
			dot = -1.0f;
		}
		if (dot > 1.0f) {
			dot = 1.0f;
		}
		return (float) Math.acos(dot);
	}

	public float angle() {
		return (float) Math.atan2(y, x);
	}

	public float theta() {
		float theta = (float) Math.toDegrees(Math.atan2(y, x));
		if ((theta < -360) || (theta > 360)) {
			theta = theta % 360;
		}
		if (theta < 0) {
			theta = 360 + theta;
		}
		return theta;
	}

	public Vector2f rotate(float cos, float sin) {
		float newX = x * cos - y * sin;
		float newY = x * sin + y * cos;
		x = newX;
		y = newY;
		return this;
	}
	
	@Override
	public String toString() {
		return getClass().getSimpleName() + " {x=" + x + ", y=" + y + ", len=" + length() + ", theta=" + theta() + "}";
	}

	public static Vector2f truncate(Vector2f vec, float limite) {
		float value = limite / vec.length();
		if (value < 1f) {
			vec.x = vec.x * value;
			vec.y = vec.y * value;
		}
		return vec;
	}
	
	public static Vector2f interpolation(Vector2f v1, Vector2f v2, float blend) {
		v1.x = (v1.x + (v2.x - v1.x) * blend);
		v1.y = (v1.y + (v2.y - v1.y) * blend);
	    return v1;
	}

	public static float distanceSq(Vector2f v1, Vector2f v2) {
		float dx = v2.x - v1.x;
		float dy = v2.y - v1.y;
		return dx * dx + dy * dy;
	}

	public static float distance(Vector2f v1, Vector2f v2) {
		float dx = v2.x - v1.x;
		float dy = v2.y - v1.y;
		return (float) Math.sqrt(dx * dx + dy * dy);
	}
	
	public static Vector2f multAdd(Vector2f v1, float value, Vector2f v2) {
		v2.x = v2.x + (v1.x * value);
		v2.y = v2.y + (v1.y * value);
		return v1;
	}
	
}
